//! `std::thread` 模块的测试用例
//!
//! 本文件包含对 `std::thread` 中线程创建和管理功能的测试。

#[cfg(test)]
mod tests {
    use std::thread;
    use std::time::Duration;

    /// 测试创建一个简单的线程
    #[test]
    fn test_spawn_thread() {
        // `thread::spawn` 创建一个新线程并立即执行闭包
        let handle = thread::spawn(|| {
            // 这是在新线程中执行的代码
            println!("Hello from a new thread!");
            thread::sleep(Duration::from_millis(10));
            42
        });

        // `join` 会等待线程执行完毕，并返回一个 `Result`
        // 如果线程 panic，`join` 会返回 `Err`
        let result = handle.join().unwrap();

        assert_eq!(result, 42);
    }

    /// 测试使用 `move` 关键字将数据所有权转移到线程中
    #[test]
    fn test_move_ownership_to_thread() {
        let data = vec![1, 2, 3];

        // 使用 `move` 将 `data` 的所有权转移到闭包中
        let handle = thread::spawn(move || {
            // 现在 `data` 归此线程所有
            println!("Data in thread: {:?}", data);
            assert_eq!(data.len(), 3);
        });

        // 此时 `data` 在主线程中已不可用，下面的代码会编译失败
        // println!("{:?}", data);

        handle.join().unwrap();
    }

    /// 测试线程构建器 `Builder`
    #[test]
    fn test_thread_builder() {
        let builder = thread::Builder::new()
            .name("my-test-thread".into()) // 设置线程名称
            .stack_size(32 * 1024); // 设置栈大小

        let handle = builder
            .spawn(|| {
                // 检查线程名称
                assert_eq!(thread::current().name(), Some("my-test-thread"));
                println!("Running in a thread named: {:?}", thread::current().name());
            })
            .unwrap();

        handle.join().unwrap();
    }

    /// 测试线程局部变量 `thread_local!`
    #[test]
    fn test_thread_local() {
        use std::cell::RefCell;

        // 定义一个线程局部变量
        thread_local!(static FOO: RefCell<u32> = RefCell::new(1));

        FOO.with(|f| {
            // 在主线程中访问
            assert_eq!(*f.borrow(), 1);
            *f.borrow_mut() = 2;
            assert_eq!(*f.borrow(), 2);
        });

        // 在一个新线程中访问
        let handle = thread::spawn(|| {
            FOO.with(|f| {
                // 新线程有它自己的 FOO 副本，初始值为 1
                assert_eq!(*f.borrow(), 1);
                *f.borrow_mut() = 3;
                assert_eq!(*f.borrow(), 3);
            });
        });

        handle.join().unwrap();

        // 再次在主线程中访问，值仍然是 2
        FOO.with(|f| {
            assert_eq!(*f.borrow(), 2);
        });
    }

    /// 测试 `thread::park` 和 `thread::unpark`
    #[test]
    fn test_park_unpark() {
        let parked_thread = thread::current();

        let handle = thread::spawn(move || {
            thread::sleep(Duration::from_millis(10));
            println!("Unparking the main thread.");
            parked_thread.unpark(); // 唤醒主线程
        });

        println!("Parking the main thread.");
        thread::park(); // 阻塞主线程，直到被 unpark
        println!("Main thread unparked.");

        handle.join().unwrap();
    }
}
